package com.wish.mmapio;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by tantexian on 2016/12/4.
 */
public class Mmap {
    private static String fileNameTest = "./tmp110";
    private static String fileNameTest1 = "./tmp111";

    private static String fileName = "E://tmp/idea.exe";

    private static String fileName1 = "E://tmp/test2.txt";

    private static String fileName2 = "E://tmp/append.txt";

    // 当前写到什么位置
    private final static AtomicInteger wrotePostion = new AtomicInteger(0);

    private final static long fileSize = 1024 * 1024 * 10;

    private static MappedByteBuffer mappedByteBuffer;
    private static FileChannel fileChannel;

    public static void main(String[] args) {
        //System.out.println("test.........");
        //mapedFileWrite();
        // mappedFileReadAndWrite();
        /*String msg = "hello word!!!\n";
        int len = 100;
        for(int i=0; i < len; i++){
            appendMsg2Mappend(msg + i);
        }*/

        /*CharBuffer buffer = CharBuffer.allocate(8);
        buffer.position(3).limit(6).mark().position(5);


        System.out.println(buffer.position());
        System.out.println(buffer.limit());


        CharBuffer duplicateBuffer = buffer.slice();
        System.out.println(duplicateBuffer.position());
        System.out.println(duplicateBuffer.limit());

        duplicateBuffer.clear();
        System.out.println(duplicateBuffer.position());
        System.out.println(duplicateBuffer.limit());*/


        try {
            long start = System.currentTimeMillis();
            fileChannel = new RandomAccessFile(fileNameTest, "rw").getChannel();
            mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);

            String msg = "Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!Hello word!";
            int len = 11000;
            for (int i = 0; i < len; i++) {
                appendMsgByMmap((msg + i + "\n").getBytes());
            }
            System.out.println("appendMsgByMmap总计耗时(ms): " + (System.currentTimeMillis() - start));


            start = System.currentTimeMillis();
            fileChannel = new RandomAccessFile(fileNameTest1, "rw").getChannel();
            for (int i = 0; i < len; i++) {
                appendMsgByfileChanal((msg + i + "\n").getBytes());
            }
            System.out.println("appendMsgByfileChanal总计耗时(ms): " + (System.currentTimeMillis() - start));

        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    public static void appendMsgByMmap(final byte[] data) {
        try {

            int currentPos = wrotePostion.get();

            // 表示还有剩余空间可以写入
            if ((currentPos + data.length) < fileSize) {
                ByteBuffer byteBuffer = mappedByteBuffer.slice();
                byteBuffer.position(currentPos);
                System.out.println("currentPos, position== " + currentPos + "|" + byteBuffer.position());

                byteBuffer.put(data);
                wrotePostion.addAndGet(data.length);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void appendMsgByfileChanal(final byte[] data) {
        try {
            ByteBuffer byteBuffer = ByteBuffer.allocate(data.length);
            byteBuffer.put(data);
            byteBuffer.flip();
            int remaining = byteBuffer.remaining();
            for (int i = 0; i < remaining; i++) {
                fileChannel.write(byteBuffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static ByteBuffer mapedFileRead() {

        try {
            RandomAccessFile fis = null;
            fis = new RandomAccessFile(fileName, "r");
            FileChannel fc = fis.getChannel();
            System.out.println("fileSize == " + fileSize);
            MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fileSize);
            return mbb.get(new byte[(int) fc.size()]);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void mapedFileWrite() {
        try {
            long start = System.currentTimeMillis();
            // FileOutputStream fos = new FileOutputStream(fileName1);
            RandomAccessFile fos = new RandomAccessFile(fileName1, "rw");
            FileChannel fc = fos.getChannel();
            ByteBuffer bb = mapedFileRead();
            MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);
            for (int i = 0; i < fileSize; i++) {
                mbb.put(i, bb.get(i));
            }
            mbb.flip();
            System.out.println("总计耗时(ms): " + (System.currentTimeMillis() - start));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private static void appendMsg2Mappend(String msg) {
        try {
            RandomAccessFile rafile = new RandomAccessFile(fileName2, "rw");
            FileChannel fileChannel = rafile.getChannel();
            MappedByteBuffer mbb = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
            mbb.put(msg.getBytes());
            mbb.force();
            fileChannel.close();
            rafile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void mappedFileReadAndWrite() {
        boolean isMmap = true;
        try {

            FileInputStream fis = new FileInputStream(fileName);
            FileOutputStream fos = new FileOutputStream(fileName + "." + System.currentTimeMillis());
            FileChannel fc = fis.getChannel();

            long fileSize = fc.size();
            ByteBuffer byteBuf = ByteBuffer.allocate((int) fileSize);
            byte[] fileBytes = new byte[(int) fileSize];


            long timeStar = System.currentTimeMillis();// 得到当前的时间
            MappedByteBuffer mbb = null;
            ByteBuffer mbbByteBuffer = null;
            if (isMmap) {
                mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
                mbbByteBuffer = mbb.get(fileBytes);
            } else {
                fc.read(byteBuf);// 1 读取

            }


            System.out.println(fc.size() / 1024);
            long timeEnd = System.currentTimeMillis();// 得到当前的时间
            System.out.println("Read time :" + (timeEnd - timeStar) + "ms");
            timeStar = System.currentTimeMillis();

            if (isMmap) {

                mbb.put(mbbByteBuffer);

                mbb.flip();
            } else {
                fos.write(fileBytes);//2.写入
            }


            timeEnd = System.currentTimeMillis();
            System.out.println("Write time :" + (timeEnd - timeStar) + "ms");
            fos.flush();
            fc.close();
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
